package it.gtd.swimpool.model.business;

import com.google.common.annotations.Beta;
import com.google.common.annotations.VisibleForTesting;
import it.gtd.swimpool.model.entity.FriendshipRequest;
import it.gtd.swimpool.model.entity.User;

import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import java.util.List;

import static com.google.common.base.Preconditions.*;

@Stateless
@LocalBean
@Beta
public class FriendshipManager {
    @PersistenceContext
    private EntityManager entityManager;

    public FriendshipManager() {
    }

    @VisibleForTesting
    FriendshipManager(EntityManager entityManager) {
        this();

        checkNotNull(entityManager, "entityManager can't be null");

        this.entityManager = entityManager;
    }

    public void sendRequest(User sender, User target) {
        checkNotNull(sender, "sender can't be null");
        checkNotNull(target, "target can't be null");
        checkArgument(!sender.getFriends().contains(target) && !target.getFriends().contains(sender),
                sender.getEmail() + " can't send a friendship request because is alredy friend with " + target.getEmail());

        FriendshipRequest friendshipRequest = new FriendshipRequest(sender, target);

        entityManager.persist(friendshipRequest);

        checkState(entityManager.contains(friendshipRequest), "FriendshipRequest isn't managed before persistence");
    }

    public void accept(FriendshipRequest request) {
        checkNotNull(request, "request can't be null");
        checkArgument(entityManager.contains(request), "FriendshipRequest not contained into entityManager");

        request.getSender().addFriend(
                request.getTarget()
        );

        request.getTarget().addFriend(
                request.getSender()
        );

        entityManager.remove(request);

        checkState(request.getSender().getFriends().contains(request.getTarget()),
                "sender friendlist doesn't contain target");
        checkState(request.getTarget().getFriends().contains(request.getSender()),
                "target friendlist doesn't contain sender");
        checkState(!entityManager.contains(request), "friendship request is managed yet");
    }

    public void decline(FriendshipRequest request) {
        checkNotNull(request, "request can't be null");
        checkArgument(entityManager.contains(request), "FriendshipRequest not contained into entityManager");

        entityManager.remove(request);

        checkState(!entityManager.contains(request), "friendship request is managed yet");
    }

    public void removeFriendship(User remover, User friend) {
        checkNotNull(remover, "remover can't be null");
        checkNotNull(friend, "friend can't be null");
        checkArgument(entityManager.contains(remover), "Remover isn't managed entity");
        checkArgument(entityManager.contains(friend), "Friend isn't managed entity");
        checkArgument(remover.getFriends().contains(friend),
                "remover friendlist doesn't contain friend");
        checkArgument(friend.getFriends().contains(remover),
                "friend friendlist doesn't contain remover");

        remover.removeFriend(friend);
        friend.removeFriend(remover);

        checkState(!remover.getFriends().contains(friend),
                "remover friendlist does contain friend");
        checkState(!friend.getFriends().contains(remover),
                "friend friendlist does contain remover");
    }

    public List<FriendshipRequest> getRequests(User target) {
        TypedQuery<FriendshipRequest> query = entityManager.createNamedQuery("FriendshipRequest.byTargetId", FriendshipRequest.class);
        query.setParameter("id", target.getId());
        return query.getResultList();
    }
}
